# -*- coding: utf-8 -*-
"""
Module Description: 时装称号变更方法
Date: 2017/11/22
Author: FQ
"""
from pyshare.const.enums.remote_service_switch import ServiceSwitch
from pyshare.dal.repository_impl import RoleRepository, TitleHistoryRepository, TitleRepository, ItemRepository, \
    RankAllianceMemberRecordRepository
from pyshare.dal.gameconfig.query import getProfile, getProfileList
from pyshare.const.enums.item import ItemType, ClothesStatus
import pyshare.framework.distribute.mutex as mutex
from pyshare.distributed.area_lock_define import RoleLock as RoleBehaviorLock
from pyshare.game_logs.saint_and_monarch_log import SaintAndMonarchEventLog
from pyshare.utils import push_utils
from common.service_config import get_app_id, get_remote_service_switch
from pyshare.redis_cache.base_redis_cache import RedisCache
from pyshare.redis_cache.area_cache_key_define import CrossLeaderBoardClothesCache, CrossLeaderBoardTitleCache
from pyshare.core.context import temporary_ctx
from pyshare.distributed.area_lock_define import ActivityLock
from pyshare.const.enums.title import TitleStatus, IsShowInHouse, TitleId, IsNewData, Score, TitleTimeType


class ClothesManager(object):
    """
    公有时装变更封装
    1.活动榜单

    """

    def __init__(self, field, value, new_owner_rid=None, cfg_list=None):
        self.clothes_cfg_list = cfg_list if cfg_list else getProfileList('TcItemClothes', **{field: value})

        if not self.clothes_cfg_list:
            return

        for cfg in self.clothes_cfg_list:
            if cfg.Sex == 1:
                self.male_clothes_id = cfg.ItemId
            else:
                self.female_clothes_id = cfg.ItemId

        self.clothes_id_list = [self.male_clothes_id, self.female_clothes_id]
        self.new_clothes = None
        self.old_clothes = None
        self.old_owner_rid = None
        self.new_owner_rid = new_owner_rid

    def is_need_change(self):
        """检测是否需要变换拥有者"""
        return False if not self.clothes_cfg_list else True

    def return_clothes_id(self, sex):
        return self.male_clothes_id if sex == 1 else self.female_clothes_id

    @staticmethod
    def push_clothes(clothes_id, sex, rid):
        """
        当前时装推送
        :param clothes_id: 时装id
        :param sex: 性别
        :param rid: 角色id
        :return:
        """
        push_utils.call_push_data(
            push_id=push_utils.PushId.HEAD_ID_CHANGE,
            data={
                "HeadId": clothes_id,
                "Sex": sex
            },
            send_rid_list=[rid]
        )

    @staticmethod
    def push_clothes_change(clothes_id, rid, status_type):
        """
        时装变更推送
        :param clothes_id: 时装id
        :param rid: 角色id
        :param status_type: 时装变更情况 enum ClothesStatus
        :return:
        """
        push_utils.call_push_data(
            push_id=push_utils.PushId.CLOTHES_CHANGE,
            data={
                "ItemType": ItemType.Clothes,
                "ItemId": clothes_id,
                "GetFlag": status_type
            },
            send_rid_list=[rid]
        )

    def create_new_clothes(self, role=None, check_first=False):
        """创建时装记录"""
        role = role if role else RoleRepository.get_by_rid(self.new_owner_rid)
        self.new_clothes = self.return_clothes_id(role.sex)
        if check_first and ItemRepository.get_by_rid_itemtype_itemid(
                rid=self.new_owner_rid, item_type=ItemType.Clothes, item_id=self.new_clothes):
            return
        ItemRepository.create(rid=self.new_owner_rid,
                              item_type=ItemType.Clothes,
                              item_id=self.new_clothes,
                              count=1)

    def change_old_owner_clothes(self):
        """修改 old owner 默认时装"""
        with mutex.KeyMutex(RoleBehaviorLock.G_ROLE_MODIFY_CLOTHES_LOCK.format(RoleGuid=self.old_owner_rid)):
            old_role = RoleRepository.get_by_rid(self.old_owner_rid)
            if old_role and old_role.head_id == self.old_clothes:
                c = ItemRepository.get_forever_by_rid_itemtype(rid=self.old_owner_rid, item_type=ItemType.Clothes)
                c_cfg = getProfile('TcItemClothes', ItemId=c.item_id)
                old_role.head_id = c.item_id
                RoleRepository.save(old_role)
                self.push_clothes(c.item_id, c_cfg.Sex, self.old_owner_rid)
            self.push_clothes_change(self.old_clothes, self.old_owner_rid, ClothesStatus.Lost)

    def new_owner(self, first_rid=None, role=None, is_push=False):
        """
        新拥有者处理
        :param first_rid: 第一名
        :param role: 角色适配器实例
        :param is_push: 是否推送消息
        :return: 是否变更
        """
        self.new_owner_rid = first_rid if first_rid else self.new_owner_rid
        with ItemRepository.lock(ItemType=ItemType.Clothes, ItemId=self.male_clothes_id):
            with ItemRepository.lock(ItemType=ItemType.Clothes, ItemId=self.female_clothes_id):
                clothes = ItemRepository.get_by_itemtype_itemid_list(item_type=ItemType.Clothes,
                                                                     item_id_list=self.clothes_id_list)
                if clothes:
                    self.old_clothes = clothes.item_id
                    self.old_owner_rid = clothes.role_guid
                    if clothes.role_guid == self.new_owner_rid:
                        return False
                    ItemRepository.delete(clothes)

                self.create_new_clothes(role=role)
        if is_push:
            self.push_clothes_change(self.new_clothes, self.new_owner_rid, ClothesStatus.Get)
        return True

    def old_owner(self):
        """
        上一个拥有者处理
        :return:
        """
        if self.old_owner_rid and self.old_owner_rid != self.new_owner_rid:
            self.change_old_owner_clothes()


class CrossClothesManager(ClothesManager):
    """
    跨服榜单 时装
    2.跨服榜单：国力
    缓存格式: [rid, server_id, clothes_id]
    """

    def __init__(self, value, new_owner_rid, new_server_id):
        super(CrossClothesManager, self).__init__('LeaderBoardType', value, new_owner_rid=new_owner_rid)

        # 缓存
        self.key = CrossLeaderBoardClothesCache.format(app_id=get_app_id(), leader_board_type=value)
        self.cache = RedisCache('')
        data = self.cache.get_cache(self.key, need_loads=True)

        self.old_owner_rid = data[0] if data else None
        self.old_server_id = data[1] if data else None
        self.old_clothes = data[2] if data else None
        self.new_server_id = new_server_id

    def set_clothes_cache(self):
        """更新缓存"""
        data = [self.new_owner_rid, self.new_server_id, self.new_clothes]
        self.cache.set_cache(self.key, data, need_dumps=True, valid_sec=None)

    def new_owner(self, first_rid=None, role=None, is_push=False):
        """
        新拥有者处理
        :param first_rid: 第一名
        :param role: 角色适配器实例
        :param is_push: 是否推送消息
        :return: 是否变更
        """
        self.new_owner_rid = first_rid if first_rid else self.new_owner_rid
        if not self.new_owner_rid or self.new_owner_rid == self.old_owner_rid:
            return False

        # 访问 new owner 区服
        with temporary_ctx(server_id=self.new_server_id):
            self.create_new_clothes(role=role, check_first=True)

            # 推送时装
            if is_push:
                self.push_clothes_change(self.new_clothes, self.new_owner_rid, ClothesStatus.Get)
            # 更新缓存
            self.set_clothes_cache()
        return True

    def old_owner(self):
        """
            上一个拥有者处理
            :return:
        """
        if self.old_owner_rid and self.old_owner_rid != self.new_server_id:
            # 访问 old owner 区服
            with temporary_ctx(server_id=self.old_server_id):
                with ItemRepository.lock(ItemType=ItemType.Clothes, ItemId=self.old_clothes):
                    # 删除 old owner 时装记录
                    ItemRepository.delete_by_rid_itemtype_itemid(rid=self.old_owner_rid,
                                                                 item_type=ItemType.Clothes,
                                                                 item_id=self.old_clothes)
                    # 判断并处理old owner 当前时装需要更换
                    self.change_old_owner_clothes()


# ==============================我是分界线=========================================

class BaseTitleManager(object):
    """
    称号变更封装
    """

    def __init__(self, field, value, new_owner_rid, score=Score.Zero, cfg=None):
        cfg = cfg if cfg else getProfile('TcTitle', **{field: value})
        self.title_id = cfg.TitleId if cfg else None
        self.old_owner_rid = None
        self.new_owner_rid = new_owner_rid
        self.score = score
        from app.area.core.component_center import ComponentCenter
        self.cc = ComponentCenter()

    def is_need_change(self):
        """检测是否配置满足变更条件"""
        return False if not self.title_id else True

    @staticmethod
    def push_title(title_id, rid_list, status_type, server_id=None,
                   is_time_limit=TitleTimeType.Forever, expire_time='2010-01-01 00:00:00'):
        """
        称号推送
        :param title_id: 称号id
        :param rid_list: 角色id列表
        :param status_type: 称号变更情况 enum TitleStatus
        :param server_id: 区服id
        :param is_time_limit: 是否时间限制
        :param expire_time: 过期时间
        :return:
        """
        push_utils.call_push_data(
            push_id=push_utils.PushId.ROLE_TITLE,
            data={
                "TitleId": title_id,
                "GetFlag": status_type,
                "IsTimeLimit": is_time_limit,
                "ExpireTime": expire_time
            },
            send_rid_list=rid_list,
            server_id=server_id
        )

    def set_new_owner_title(self, role=None):
        """new owner 如果没有设置称号，则将该称号设成当前称号"""
        with mutex.KeyMutex(RoleBehaviorLock.G_ROLE_MODIFY_TITLE_LOCK.format(RoleGuid=self.new_owner_rid)):
            role = role if role else RoleRepository.get_by_rid(self.new_owner_rid)
            if not role.title_id:
                role.title_id = self.title_id
                RoleRepository.save(role)

    def change_old_owner_title(self):
        """old owner 修改当前称号，如果当前称号为 self.title """
        with mutex.KeyMutex(RoleBehaviorLock.G_ROLE_MODIFY_TITLE_LOCK.format(RoleGuid=self.old_owner_rid)):
            old_role = RoleRepository.get_by_rid(self.old_owner_rid)
            if old_role.title_id == self.title_id:
                old_role.title_id = TitleId.Default
                RoleRepository.save(old_role)
            # 告知旧拥有者失去称号
            self.push_title(self.title_id, [old_role.role_guid], TitleStatus.Lost)

    def new_owner(self, new_owner_rid=None, role=None, is_push=False):
        """
        称号 new owner
        :param new_owner_rid: 外部传入的 new owner rid
        :param role: 角色实例
        :param is_push: 是否推送标识
        :return:
        """
        self.new_owner_rid = new_owner_rid if new_owner_rid else self.new_owner_rid
        with TitleRepository.lock(TitleId=self.title_id):

            record = TitleRepository.get_forever_by_titleid(self.title_id)
            if record:
                self.old_owner_rid = record.role_id
                if record.role_id == self.new_owner_rid:
                    # new owner = ole owner 不做处理
                    return False

                # 删除 old owner
                TitleRepository.delete(record)

            # 添加称号 基类方法默认显示在名君殿
            self.cc.title.add_title(self.new_owner_rid, self.title_id,
                                    is_push=is_push, is_show_in_house=IsShowInHouse.Is)

        self.set_new_owner_title()
        return True

    def old_owner(self):
        """
        old owner 变更处理
        :return:
        """
        if self.old_owner_rid and self.old_owner_rid != self.new_owner_rid:
            self.change_old_owner_title()


class ActivityTitleManager(BaseTitleManager):
    """
    活动称号变更
    明君殿展示的称号
    """

    def __init__(self, activity_type, activity_id, new_owner_rid, score=Score.Zero, cfg=None):
        super(ActivityTitleManager, self).__init__('ActivityType', activity_type,
                                                   new_owner_rid=new_owner_rid,
                                                   score=score,
                                                   cfg=cfg)
        self.activity_id = activity_id

    def new_history(self):
        """创建历史记录"""
        with mutex.KeyMutex(ActivityLock.TITLE_CHANGE.format(ActivityId=self.activity_id)):
            if not TitleHistoryRepository.get_by_id(self.activity_id):
                switch = get_remote_service_switch(ServiceSwitch.MonarchTitleIsNewData)
                if not switch:
                    TitleHistoryRepository.create(self.activity_id,
                                                  self.title_id,
                                                  self.new_owner_rid,
                                                  is_new=IsNewData.Not)
                else:
                    TitleHistoryRepository.create(self.activity_id, self.title_id, self.new_owner_rid, score=self.score)
                    # 获得明君称号事件埋点
                SaintAndMonarchEventLog.generate_monarch_history_log(self.new_owner_rid, self.title_id, self.activity_id,
                                                                     self.score)


class CrossTitleManager(BaseTitleManager):
    """
    跨服称号变更管理
    跨服榜单 不显示在明君殿
    缓存格式：[rid, server_id]
    """

    def __init__(self, leader_board_type, new_owner_rid, new_server_id):
        super(CrossTitleManager, self).__init__('LeaderBoardType', leader_board_type, new_owner_rid=new_owner_rid, score=0)

        # 缓存
        self.cache = RedisCache('')
        self.key = CrossLeaderBoardTitleCache.format(app_id=get_app_id(), leader_board_type=leader_board_type)
        data = self.cache.get_cache(self.key, need_loads=True)

        self.old_owner_rid = data[0] if data else None
        self.old_server_id = data[1] if data else None
        self.new_server_id = new_server_id

    def set_new_owner_cache(self):
        """更新缓存"""
        self.cache.set_cache(self.key, [self.new_owner_rid, self.new_server_id], need_dumps=True, valid_sec=None)

    def new_owner(self, new_owner_rid=None, role=None, is_push=False):
        self.new_owner_rid = new_owner_rid if new_owner_rid else self.new_owner_rid
        if not self.new_owner_rid or self.new_owner_rid == self.old_owner_rid:
            return False

        # 访问 new owner 区服
        with temporary_ctx(server_id=self.new_server_id):
            self.cc.title.add_title(self.new_owner_rid, self.title_id, is_one_push=is_push)
            self.set_new_owner_title()
            # 更新缓存
            self.set_new_owner_cache()
        return True

    def old_owner(self):
        """
        old owner 变更处理
        :return:
        """
        if self.old_owner_rid and self.old_owner_rid != self.new_owner_rid:
            # 访问 old owner 区服
            with temporary_ctx(server_id=self.old_server_id):
                with TitleRepository.lock(TitleId=self.title_id):
                    # 删除称号
                    TitleRepository.delete_all_old_title_owner(self.title_id, (self.old_owner_rid,))

                    self.change_old_owner_title()


class BaseAllianceTitleManager(object):
    """
    联盟称号变更管理基类
    (多人称号)
    """

    def __init__(self, field, value, new_alliance_id, score=Score.Zero, cfg=None):
        cfg = cfg if cfg else getProfile('TcTitle', **{field: value})
        self.title_id = cfg.TitleId if cfg else None
        self.alliance_id = new_alliance_id
        self.add_rid_list = set()
        self.del_rid_list = set()
        self.new_rid_list = set()
        self.leader_rid = None
        self.old_leader_rid = None
        self.score = score
        from app.area.core.component_center import ComponentCenter
        self.cc = ComponentCenter()

    def is_need_change(self):
        """检测是否配置满足变更条件"""
        return False if not self.title_id else True

    def get_owner_list(self):
        """返回拥有称号的rid列表"""
        rid_list = []
        for t in TitleRepository.filter_forever_by_titleid(self.title_id):
            if t.is_show_in_house == 1:
                self.old_leader_rid = t.role_id
            rid_list.append(t.role_id)
        return rid_list

    def get_role_alliance_map(self):
        """
        获取角色和联盟，称号的关联
        :return:
        """
        raise NotImplementedError

    def set_change_owners(self):
        """
        返回称号有变动的角色列表
        :return:
        """
        old_rid_list = self.get_owner_list()
        self.new_rid_list = self.get_role_alliance_map()
        self.del_rid_list = set(old_rid_list) - set(self.new_rid_list)
        self.add_rid_list = set(self.new_rid_list) - set(old_rid_list)

    def is_show_in_house(self, rid):
        """是否显示明君殿"""
        raise NotImplementedError

    def _do_all_owner(self):

        # 修改当前没有设置称号的 new owner
        RoleRepository.update_title_new_owner_for_noset_title_role(list(self.new_rid_list), title_id=self.title_id)

        add_rid_dict = dict()
        for rid in self.new_rid_list:
            add_rid_dict[rid] = self.is_show_in_house(rid)
        self.cc.title.add_many_role_title_by_dict(add_rid_dict, self.title_id)

        # 修改盟战有变更的IsShowInHouse
        if self.old_leader_rid is not None and self.old_leader_rid not in self.del_rid_list and self.old_leader_rid != \
                self.leader_rid:
            TitleRepository.update_is_show_in_house(self.old_leader_rid, self.title_id, is_show_in_house=0)

        if self.old_leader_rid != self.leader_rid and self.leader_rid not in self.add_rid_list:
            TitleRepository.update_is_show_in_house(self.leader_rid, self.title_id, is_show_in_house=1)

    def new_all_owner(self, is_push=True):
        """批量处理new owner"""

        with TitleRepository.lock(TitleId=self.title_id):

            # 初始化owner数据
            self.set_change_owners()

            self._do_all_owner()
        if is_push:
            # 推送信息
            BaseTitleManager.push_title(self.title_id, list(self.add_rid_list), TitleStatus.Get)

    def old_all_owner(self, is_push=True):
        """批量处理 old owner"""
        # 删除旧的拥有者记录
        if self.del_rid_list:
            self.cc.title.delete_rid_title(list(self.del_rid_list), self.title_id, is_push=is_push)

    def new_single_owner(self, map_record, is_push=True):
        """
        单独处理 new owner 用于领奖
        :param map_record: 角色联盟活动关联记录
        :param is_push:
        :return:
        """

        if not map_record:
            return False

        with TitleRepository.lock(TitleId=self.title_id):
            old_title = TitleRepository.get_by_titleid_isshowinhouse(self.title_id, is_show_in_house=IsShowInHouse.Is)
            if old_title and old_title.role_id != map_record.role_guid and map_record.is_leader:
                TitleRepository.update_is_show_in_house(old_title.role_id, self.title_id,
                                                        is_show_in_house=IsShowInHouse.Not)
            title = TitleRepository.get_by_rid_titleid(map_record.role_guid, self.title_id)
            if title:
                if title.is_show_in_house != map_record.is_leader:
                    title.is_show_in_house = map_record.is_leader
                    TitleRepository.save(title)
                return False
            # 添加称号
            self.cc.title.add_title(rid=map_record.role_guid, title_id=self.title_id,
                                    is_show_in_house=map_record.is_leader, is_push=is_push, is_wear_for_notset=True)

            if map_record.is_leader:
                self.leader_rid = map_record.role_guid
        return True


class ActivityAllianceATitleManager(BaseAllianceTitleManager):
    """
    联盟活动 称号
    """

    def __init__(self, activity_type, activity_id, alliance_id, score=Score.Zero, cfg=None):
        super(ActivityAllianceATitleManager, self).__init__('ActivityType', activity_type, alliance_id, score=score, cfg=cfg)
        self.activity_id = activity_id

    def new_history(self):
        """创建历史记录"""
        if not self.leader_rid:
            return

        with mutex.KeyMutex(ActivityLock.TITLE_CHANGE.format(ActivityId=self.activity_id)):
            if not TitleHistoryRepository.get_by_id(self.activity_id):
                switch = get_remote_service_switch(ServiceSwitch.MonarchTitleIsNewData)
                if not switch:
                    TitleHistoryRepository.create(self.activity_id,
                                                  self.title_id,
                                                  self.leader_rid,
                                                  is_new=IsNewData.Not)
                else:
                    TitleHistoryRepository.create(self.activity_id, self.title_id, self.leader_rid, score=self.score)
                # 获得明君称号事件埋点
                SaintAndMonarchEventLog.generate_monarch_history_log(self.leader_rid, self.title_id, self.activity_id,
                                                                     self.score)

    def is_show_in_house(self, rid):
        """是否显示明君殿"""
        return 0 if rid != self.leader_rid else 1

    def get_role_alliance_map(self):
        """
        获取角色和联盟，称号的关联
        :return:
        """
        new_rid_list = []
        for r in RankAllianceMemberRecordRepository.filter_by_allianceid_activityid(self.alliance_id, self.activity_id):
            new_rid_list.append(r.role_guid)
            if r.is_leader:
                self.leader_rid = r.role_guid

        return new_rid_list


class SiegeTitleManager(BaseAllianceTitleManager):
    """
    龙城活动 称号
    """

    def __init__(self, alliance_id, cfg=None):
        super(SiegeTitleManager, self).__init__('ActivityType', 1002, alliance_id, cfg=cfg)

    def is_show_in_house(self, rid):
        """是否显示明君殿"""
        return 0

    def get_role_alliance_map(self):
        """
        获取角色和联盟，称号的关联
        :return:
        """
        from app.area.core.component_center import ComponentCenter
        cc = ComponentCenter()
        siege_users = cc.siege.siege_map_cache.get_alliance_members(self.alliance_id)
        return [key.split('#')[1] for key in siege_users]
